package com.atguigu.tingshu.common.login;


import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author: atguigu
 * @create: 2025-07-17 16:44
 */
@Slf4j
@Aspect
@Component
public class GuiGuLoginAspect {
    @Autowired
    private RedisTemplate redisTemplate;

    @Around("execution(* com.atguigu.tingshu.*.api.*.*(..)) && @annotation(guiGuLogin)")
    public Object around(ProceedingJoinPoint pjp, GuiGuLogin guiGuLogin) throws Throwable {


        //一、前置逻辑
        log.info("前置逻辑...");
        //1.获取到请求对象
        //1.1 通过请求上下文(底层ThreadLocal)对象获取请求对象 RequestAttributes接口
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //1.2 将接口类型强转为ServletRequestAttributes实现类
        ServletRequestAttributes sra = (ServletRequestAttributes) requestAttributes;
        //1.3 获取请求对象
        HttpServletRequest request = sra.getRequest();

        //2.获取请求头token中令牌
        String token = request.getHeader("token");

        //3.查询Redis中用户基本信息
        //3.1 构建在登录成功后存入Redis用户信息Key 形式=前缀+用户令牌
        String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        //3.2 查询在登录成功后存入Redis用户基本信息 UserInfoVo
        UserInfoVo userInfoVo = (UserInfoVo) redisTemplate.opsForValue().get(loginKey);

        //4.如果Redis中登录用户信息为空切目标方法要求必须登录 抛出异常 前端要求响应业务状态码为208，前端引导用户登录
        if (userInfoVo == null && guiGuLogin.required()) {
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }

        //5.如果Redis中用户信息存在，获取用户ID，将用户ID存入ThreadLocal 方便后续javaEE三层获取用户ID
        if (userInfoVo != null) {
            AuthContextHolder.setUserId(userInfoVo.getId());
        }
        //二、目标方法 controller使用使用自定义认证注解的方法
        Object result = pjp.proceed();
        //三、后置逻辑
        log.info("后置逻辑...");
        //6.避免ThreadLocal引发的内存泄漏，清理ThreadLocal
        AuthContextHolder.removeUserId();
        return result;
       /* //一、前置逻辑
        log.info("前置逻辑...");
        //1.获取令牌，查user信息
        //1.1请求对象
        //1.1.1请求上下文对象
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //1.1.2请求对象
        ServletRequestAttributes sra = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = sra.getRequest();
        //1.2请求头
        String token = request.getHeader("token");
        //2.查询存入redis的信息
        //2.1存入redis的key    形式=前缀+用户令牌
        String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX+token;
        //2.2存入redis的 UserInfoVo
        UserInfoVo userInfoVo = (UserInfoVo) redisTemplate.opsForValue().get(loginKey);
        //3.如果必须登录但是user信息空，抛异常，response状态码208->登录
        if (userInfoVo==null && guiGuLogin.required()){
            throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
        }
        //4.存在
        if (userInfoVo!=null){
            AuthContextHolder.setUserId(userInfoVo.getId());
        }
        //二、目标方法 controller使用使用自定义认证注解的方法
        log.info("二、目标方法执行");
        Object result = pjp.proceed();
        //三、后置逻辑
        log.info("后置逻辑...");
        return request;*/
    }
}
